package com.gs.netty.support.dispatch;

import com.gs.netty.core.dispatch.FrameworkDispatch;
import com.gs.netty.core.handler.HandlerExecutionChain;
import com.gs.netty.core.handler.HandlerMapping;
import com.gs.netty.core.handler.adapter.HandlerAdapter;
import com.gs.netty.core.handler.method.HandlerMethod;
import com.gs.netty.core.resolver.HandlerExceptionResolver;
import com.gs.netty.core.resolver.HandlerMethodReturnValueHandler;

import com.gs.netty.websocket.remoting.req.Request;
import com.gs.netty.websocket.remoting.req.SocketRequest;
import com.gs.netty.websocket.remoting.resp.SocketResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.util.Map;

@Slf4j
public class WebSocketDispatch extends FrameworkDispatch<SocketRequest, SocketResponse> implements ApplicationContextAware {

    public WebSocketDispatch() {

    }
    private boolean useEventLog =true;

    public boolean isUseEventLog() {
        return useEventLog;
    }

    public void setUseEventLog(boolean useEventLog) {
        this.useEventLog = useEventLog;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    private ApplicationContext applicationContext;

    @Override
    public void doDispatch(SocketRequest request, SocketResponse response){
        HandlerExecutionChain chain = null;
        try {
            // 程序处理异常try

            Exception dispatchException = null;
            try {
                // 1.找到方法处理器
                chain = getHandlerInternal(request);

                if (chain == null) {
                    noHandlerFound(request,response);
                    return;
                }
                // 获取适配器

                HandlerAdapter handlerAdapter = getHandlerAdapter(chain.getHandler());

                // 2.前置处理
                if (!chain.applyPreHandle(request, response)) {
                    return;
                }
                // 3.程序处理
               handlerAdapter.handle(request, response, chain.getHandler());

                // 4.后置处理
                chain.applyPostHandle(request, response, null);
            } catch (Exception e) {
                dispatchException  =e;
            } catch (Throwable e) {
                log.error("Dispatch Unknown exception", e);
                dispatchException = new RuntimeException("Dispatch Unknown exception",e);
            }
            // 5.结果处理
            processDispatchResult(request,response,dispatchException,chain);
        }
        // 下面这两个异常 可能会在 5.结果处理出现错误
        catch (Exception e) {
            if (chain != null) {
                chain.triggerAfterCompletion(request, response,e);
            }
        }catch (Throwable err) {
            if (chain != null) {
                chain.triggerAfterCompletion(request, response,new RuntimeException("Handler processing failed", err));
            }
        } finally {

        }
    }

    private void processDispatchResult(SocketRequest request, SocketResponse response,
                                       Exception dispatchException,
                                       HandlerExecutionChain chain) {
        HandlerMethod handler = (HandlerMethod) chain.getHandler();
        if (dispatchException != null ) {
            //证明 出现异常 ，找到异常处理器
           processHandlerException(request,response,dispatchException,handler);
        }

        if (chain != null) {
            chain.triggerAfterCompletion(request, response, dispatchException);
        }
    }

    private void processHandlerException(Request request, SocketResponse response, Exception ex, Object handler) {
        for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
            if (resolver.support(request)) {
                resolver.resolveException(request, response, handler, ex);
                break;
            }
        }

    }

    /**
     * 初始化处理器
     */

    @Override
    protected void initHandler() {
        /**
         * 处理器映射器
         */
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings.addAll(matchingBeans.values());
        }

        // 适配器
        Map<String, HandlerAdapter> handlerAdapterMap =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters.addAll(handlerAdapterMap.values());
        }


        Map<String, HandlerExceptionResolver> handlerExceptionResolverMap =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerExceptionResolver.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerExceptionResolvers.addAll(handlerExceptionResolverMap.values());
        }


        Map<String, HandlerMethodReturnValueHandler> returnValueHandlerMap =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, HandlerMethodReturnValueHandler.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMethodReturnValueHandlers.addAll(returnValueHandlerMap.values());
        }
    }

    @Override
    protected void noHandlerFound(SocketRequest request, SocketResponse response) {
        log.debug("No handler found for request command: "+ request.getCommand());
//        response.writeAndFlush(request.createRequest(ResponseCode.NO_FOUND_HANDLER,"No handler found for request: "+request.getCommand()));
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


    protected HandlerAdapter getHandlerAdapter(Object handler) throws RuntimeException {

        if (this.handlerAdapters != null) {
            // 找到请求处理适配器
            for (HandlerAdapter adapter : this.handlerAdapters) {
                if (adapter.support(handler)) {
                    return adapter;
                }
            }
        }
        throw new IllegalStateException("No adapter for handler [" + handler +
                "]: The EnableWebSocketDispatch configuration needs to include a HandlerAdapter that supports this handler");
    }

}
